package org.goldenport.g3.messages

import java.io._
import java.net.URL
import org.goldenport.g3.G3Message
import org.apache.http.HttpResponse
import com.asamioffice.goldenport.io.UIO

/**
 * @since   May. 22, 2010
 * @version Jul. 25, 2010
 * @author  ASAMI, Tomoharu
 **/
abstract class Blob extends G3Message {
  val IN_MEMORY_SIZE = 8192
  def openInputStream(): InputStream

  def sizeOption(): Option[Long] = None

  def asBytes(): Array[Byte] = {
    val in = openInputStream()
    try {
      UIO.stream2Bytes(in)
    } finally {
      in.close()
    }
  }

  def asBytesOption(): Option[Array[Byte]] = {
    sizeOption match {
      case Some(size) if size <= IN_MEMORY_SIZE => Some(asBytes())
      case _ => None
    }
  }


  def asClob: BlobClob = asClob()

  def asClob(encoding: String = "utf-8"): BlobClob = {
    new BlobClob(this, encoding)
  }
}

class BinaryBlob(val bytes: Array[Byte]) extends Blob {
  def openInputStream(): InputStream = {
    new ByteArrayInputStream(bytes)
  }

  override def sizeOption(): Option[Long] = Some(bytes.length)
}

class FileBlob(val file: File) extends Blob {
  def openInputStream(): InputStream = {
    new FileInputStream(file)
  }

  override def sizeOption(): Option[Long] = Some(file.length)
}

class UrlBlob(val url: URL) extends Blob {
  def openInputStream(): InputStream = {
    url.openStream()
  }
}

/*
class InputStreamBlob(val in: InputStream) extends Blob {
  
}
*/

object Blob {
  def apply(binary: Array[Byte]): BinaryBlob = {
    new BinaryBlob(binary)
  }

  def apply(file: File): FileBlob = {
    new FileBlob(file)
  }

  def apply(url: URL): UrlBlob = {
    new UrlBlob(url)
  }

  def apply(resp: HttpResponse): Blob = {
    val entity = resp.getEntity
    val length = entity.getContentLength
    val ctype = entity.getContentType
    val encoding = entity.getContentEncoding
    val content = entity.getContent
    val blob = if (length == 0) {
      apply(new Array[Byte](0))
    } else if (length <= 8192) {
      apply(UIO.stream2Bytes(content))
    } else {
      apply(UIO.stream2Bytes(content))
    }
    entity.consumeContent()
    blob
  }
}
